﻿#include "asycipc/crc32c.hpp"

#include <array>

namespace asycipc {
namespace {
constexpr uint32_t kPolynomial = 0x82F63B78u;

constexpr std::array<uint32_t, 256> BuildTable() {
  std::array<uint32_t, 256> table{};
  for (uint32_t i = 0; i < table.size(); ++i) {
    uint32_t crc = i;
    for (int j = 0; j < 8; ++j) {
      if (crc & 1U) {
        crc = (crc >> 1) ^ kPolynomial;
      } else {
        crc >>= 1;
      }
    }
    table[i] = crc;
  }
  return table;
}

constexpr std::array<uint32_t, 256> kTable = BuildTable();
}  // namespace

uint32_t Crc32c(const uint8_t* data, std::size_t length) {
  uint32_t crc = 0xFFFFFFFFu;
  for (std::size_t i = 0; i < length; ++i) {
    const uint8_t byte = data[i];
    crc = kTable[(crc ^ byte) & 0xFFu] ^ (crc >> 8);
  }
  return ~crc;
}

uint32_t Crc32c(const void* data, std::size_t length) {
  return Crc32c(static_cast<const uint8_t*>(data), length);
}

}  // namespace asycipc
